﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using xTile;
using xTile.Dimensions;
using xTile.Display;
using Microsoft.Xna.Framework;
using xTile.Layers;

namespace Broadsides2d
{
    public class World
    {
        public static World world;

        public Tile[,] tiles;
        public Port[] ports;
        private bool generated;
        public int worldSize;
        public int worldSizeInPixels;

        //XTile stuff
        public Map map;
        public XnaDisplayDevice mapDisplayDevice;
        public xTile.Dimensions.Rectangle viewport;


        public World() : this(10)
        {
        }

        public World(int worldSize)
        {
            world = this;

            this.worldSize = worldSize;
            this.worldSizeInPixels = worldSize * Tile.SIZE;

            tiles = new Tile[worldSize,worldSize];


        }

        public void setupMap()
        {
            //generateWorld();
            loadWorld();
        }

        public void loadWorld()
        {
            world.viewport = new xTile.Dimensions.Rectangle(new Size(Game1.screenX, Game1.screenY));

            Layer l = map.GetLayer("collision");

            for (int i = 0; i < tiles.GetLength(0); i++)
            {
                for (int j = 0; j < tiles.GetLength(1); j++)
                {
                    xTile.Tiles.Tile x = l.Tiles[i, j];
                    if (x == null)
                    {
                        tiles[i, j] = new Tile(i * Tile.SIZE, j * Tile.SIZE, Tile.TileType.water);
                    }
                    else
                    {
                        tiles[i, j] = new Tile(i * Tile.SIZE, j * Tile.SIZE, Tile.TileType.land);
                    }
                }
            }

            l = map.GetLayer("harbors");
            LinkedList<Port> portsList = new LinkedList<Port>();
            for (int i = 0; i < tiles.GetLength(0); i+=4)
            {
                for (int j = 0; j < tiles.GetLength(1); j+=4)
                {
                    xTile.Tiles.Tile x = l.Tiles[i/4, j/4];
                    if (x == null)
                    {
                        
                    }
                    else
                    {
                        tiles[i, j] = new Tile(i * Tile.SIZE, j * Tile.SIZE, Tile.TileType.port);
                        tiles[i, j + 1] = new Tile(i * Tile.SIZE, (j + 1) * Tile.SIZE, Tile.TileType.port);
                        tiles[i, j + 2] = new Tile(i * Tile.SIZE, (j + 2) * Tile.SIZE, Tile.TileType.port);
                        tiles[i, j + 3] = new Tile(i * Tile.SIZE, (j + 3) * Tile.SIZE, Tile.TileType.port);

                        tiles[i + 1, j]     = new Tile((i+1) * Tile.SIZE, j * Tile.SIZE, Tile.TileType.port);
                        tiles[i + 1, j+1]   = new Tile((i+1) * Tile.SIZE, (j+1) * Tile.SIZE, Tile.TileType.port);
                        tiles[i + 1, j + 2] = new Tile((i + 1) * Tile.SIZE, (j + 2) * Tile.SIZE, Tile.TileType.port);
                        tiles[i + 1, j + 3] = new Tile((i + 1) * Tile.SIZE, (j + 3) * Tile.SIZE, Tile.TileType.port);
                        
                        tiles[i + 2, j + 0] = new Tile((i + 2) * Tile.SIZE, (j + 0) * Tile.SIZE, Tile.TileType.port);
                        tiles[i + 2, j + 1] = new Tile((i + 2) * Tile.SIZE, (j + 1) * Tile.SIZE, Tile.TileType.port);
                        tiles[i + 2, j + 2] = new Tile((i + 2) * Tile.SIZE, (j + 2) * Tile.SIZE, Tile.TileType.port);
                        tiles[i + 2, j + 3] = new Tile((i + 2) * Tile.SIZE, (j + 3) * Tile.SIZE, Tile.TileType.port);

                        tiles[i + 3, j + 0] = new Tile((i + 3) * Tile.SIZE, (j + 0) * Tile.SIZE, Tile.TileType.port);
                        tiles[i + 3, j + 1] = new Tile((i + 3) * Tile.SIZE, (j + 1) * Tile.SIZE, Tile.TileType.port);
                        tiles[i + 3, j + 2] = new Tile((i + 3) * Tile.SIZE, (j + 2) * Tile.SIZE, Tile.TileType.port);
                        tiles[i + 3, j + 3] = new Tile((i + 3) * Tile.SIZE, (j + 3) * Tile.SIZE, Tile.TileType.port);

                        
                        portsList.AddLast(new Port(i+1, j+1));
                    }
                }
            }

            ports = portsList.ToArray();
            Port.connectPorts(ports);

            generated = false;
        }

        public void generateWorld(){
            generated = true;
            Random rand = new Random();

            for (int i = 0; i < tiles.GetLength(0); i++)
            {
                for (int j = 0; j < tiles.GetLength(1); j++)
                {
                    float odds = 0.05f;
                    
                    if (j > 0 && tiles[i, j - 1].getType() == Tile.TileType.land)
                    {
                        odds = 60 - Math.Max(0, j + 25 - tiles.GetLength(1))*3;
                    }
                    
                    if (i > 0 && tiles[i - 1, j].getType() == Tile.TileType.land)
                    {
                        odds = 60 - Math.Max(0, i + 25 - tiles.GetLength(0))*3;
                    }

                    if (j > 0 && i > 0 && tiles[i - 1, j - 1].getType() == Tile.TileType.land && tiles[i - 1, j].getType() == Tile.TileType.land && tiles[i, j - 1].getType() == Tile.TileType.land)
                    {
                       odds = 100;
                    }

                    if (rand.Next(1000) > odds * 10 || i < 10 || j < 10 || i > tiles.GetLength(0) - 10 || j > tiles.GetLength(1) - 10)
                    {
                        tiles[i, j] = new Tile(i * Tile.SIZE, j * Tile.SIZE, Tile.TileType.water);
                    }
                    else
                    {
                        tiles[i, j] = new Tile(i * Tile.SIZE, j * Tile.SIZE, Tile.TileType.land);
                    }
                }
            }
            //end land / water pass

            //second pass for ports
            float oddsPorts = 1;
            LinkedList<Port> portsList = new LinkedList<Port>();
            for (int i = 10; i < tiles.GetLength(0) - 10; i++)
            {
                for (int j = 10; j < tiles.GetLength(1) - 10; j++)
                {
                    float odds = 0f;

                    if (tiles[i, j].getType() == Tile.TileType.water)
                    {
                        if (tiles[i, j - 1].getType() == Tile.TileType.land)
                        {
                            odds = oddsPorts;
                        }

                        if (tiles[i - 1, j].getType() == Tile.TileType.land)
                        {
                            odds = oddsPorts;
                        }

                        if (tiles[i, j + 1].getType() == Tile.TileType.land)
                        {
                            odds = oddsPorts;
                        }

                        if (tiles[i + 1, j].getType() == Tile.TileType.land)
                        {
                            odds = oddsPorts;
                        }

                        if (rand.Next(1000) < odds * 10)
                        {
                            oddsPorts--;
                            tiles[i - 1, j - 1] = new Tile((i - 1) * Tile.SIZE, (j - 1) * Tile.SIZE, Tile.TileType.port);
                            tiles[i - 1, j + 0] = new Tile((i - 1) * Tile.SIZE, j * Tile.SIZE, Tile.TileType.port);
                            tiles[i - 1, j + 1] = new Tile((i - 1) * Tile.SIZE, (j + 1) * Tile.SIZE, Tile.TileType.port);

                            tiles[i, j - 1] = new Tile(i * Tile.SIZE, (j - 1) * Tile.SIZE, Tile.TileType.port);
                            tiles[i, j + 0] = new Tile(i * Tile.SIZE, j * Tile.SIZE, Tile.TileType.port);
                            tiles[i, j + 1] = new Tile(i * Tile.SIZE, (j + 1) * Tile.SIZE, Tile.TileType.port);

                            tiles[i + 1, j - 1] = new Tile((i + 1) * Tile.SIZE, (j - 1) * Tile.SIZE, Tile.TileType.port);
                            tiles[i + 1, j + 0] = new Tile((i + 1) * Tile.SIZE, j * Tile.SIZE, Tile.TileType.port);
                            tiles[i + 1, j + 1] = new Tile((i + 1) * Tile.SIZE, (j + 1) * Tile.SIZE, Tile.TileType.port);

                            portsList.AddLast(new Port(i, j));
                        }
                        else
                        {
                            oddsPorts += 0.001f;
                        }
                    }
                }

            }
            ports = portsList.ToArray();
            Port.connectPorts(ports);
            //end port pass
        }

        public void draw(SpriteBatch spriteBatch)
        {
            
            if (generated)
            {
                for (int i = 0; i < tiles.GetLength(0); i++)
                {
                    for (int j = 0; j < tiles.GetLength(1); j++)
                    {
                        tiles[i, j].Draw(spriteBatch);
                    }
                }
            }
            else
            {
                Vector2 v = Game1.recenter(0, 0);
                viewport.X = -(int)v.X;
                viewport.Y = -(int)v.Y;

                v.X = ((v.X + World.world.worldSizeInPixels) % World.world.worldSizeInPixels);
                v.Y = ((v.Y + World.world.worldSizeInPixels) % World.world.worldSizeInPixels);

  
                
                map.Draw(mapDisplayDevice, viewport, new Location(0,0), true);
            }

        }

        public void update(GameTime gameTime)
        {
            if (!generated)
            {
                map.Update(gameTime.ElapsedGameTime.Milliseconds);
            }
        }

        
        public bool checkForWater(float x, float y)
        {
            int i = (int)x / Tile.SIZE % worldSize;
            int j = (int)y / Tile.SIZE % worldSize;
            return tiles[i, j].getType() == Tile.TileType.water;
        }

        public bool checkForLand(float x, float y)
        {
            int i = (int)x / Tile.SIZE % worldSize;
            int j = (int)y / Tile.SIZE % worldSize;
            return tiles[i, j].getType() == Tile.TileType.land;
        }
    }
}
